package znet

import (
	"fmt"
	"zinx/Zinx/utils"
	"zinx/Zinx/ziface"
)

// IRouterHandler接口实现, 定义一个RouterHandler路由管理模块
type RouterHandler struct {
	Apis           map[uint32]ziface.IRouter // 存放不同ID对应的路由
	TaskQueue      []chan ziface.IRequest    // 每个Worker的消息队列
	WorkerPoolSize uint32                    // 工作池的Worker数量
}

// 初始化路由管理模块
func NewRouterHandler() *RouterHandler {
	return &RouterHandler{
		Apis:           make(map[uint32]ziface.IRouter),
		TaskQueue:      make([]chan ziface.IRequest, utils.Global.WorkerPoolSize),
		WorkerPoolSize: utils.Global.WorkerPoolSize,
	}
}

// 为指定ID注册路由
func (rh *RouterHandler) AddRouter(id uint32, router ziface.IRouter) {
	// 判断该ID是否已注册路由
	if _, ok := rh.Apis[id]; ok {
		fmt.Println("[RouterHandler AddRouter]fail, ID: ", id)
		return
	}
	// 绑定路由
	rh.Apis[id] = router
	fmt.Println("[RouterHandler AddRouter]success, ID: ", id)
}

// 执行ID对应路由
func (rh *RouterHandler) DoRouterHandler(request ziface.IRequest) {
	// 判断该ID是否注册路由
	router, ok := rh.Apis[request.GetID()]
	if !ok {
		fmt.Println("[RouterHandler DoRouterHandler]fail, ID: ", request.GetID(), "Route not Found")
		return
	}
	// 依次执行路由方法
	router.BeforeHandle(request)
	router.Handle(request)
	router.AfterHandle(request)
}

// 开启工作池(仅一次)
func (rh *RouterHandler) StartWorkerPool() {
	// 根据WorkerPoolSize开启指定数量的worker(goroutine)
	for i := 0; i < int(rh.WorkerPoolSize); i++ {
		// 初始化消息队列
		rh.TaskQueue[i] = make(chan ziface.IRequest, utils.Global.MaxTaskQueueLen)
		// 启动Worker
		go rh.StartOneWorker(i, rh.TaskQueue[i])
	}
}

// 启动工作池的一个Worker
func (rh *RouterHandler) StartOneWorker(workerId int, taskQueue chan ziface.IRequest) {
	fmt.Println("[Worker]id: ", workerId, " is started...")
	// 循环阻塞等待消息队列
	for {
		select {
		case request := <-taskQueue:
			rh.DoRouterHandler(request)
		}
	}
}

// 向消息队列分配请求消息
func (rh *RouterHandler) SendMsgToTaskQueue(request ziface.IRequest) {
	// 简单轮询分配给阻塞的Worker
	// 根据ConnID(连接id)分配
	workerID := request.GetConnection().GetConnID() % rh.WorkerPoolSize
	fmt.Printf("Add ConnID: %d,Request MsgID: %d,to WorkerID: %d\n",
		request.GetConnection().GetConnID(),
		request.GetID(),
		workerID)
	rh.TaskQueue[workerID] <- request
}
